﻿using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using SpaceAdventureLib.GamePlay;
using SpaceAdventureLib.Universe.SpaceObjects;
using SpaceAdventureLib.Universe.Units;
using SpaceAdventureLib.Universe.Weapons;
using TNCGameEngine.Content;


namespace SpaceAdventureLib.Universe
{
    [Serializable]
    public class Space
    {

        #region "Properties"

        private Mission mission = null;
        public Mission Mission
        {
            get { return this.mission; }
            set { this.mission = value; }
        }

        private Camera mainCamera = null;
        public Camera MainCamera
        {
            get { return this.mainCamera; }
            set { this.mainCamera = value; }
        }

        private List<Camera> otherCameras = null;
        public List<Camera> OtherCameras
        {
            get { return this.otherCameras; }
            set { this.otherCameras = value; }
        }

        private Player player = null;
        public Player Player
        {
            get { return this.player; }
            set { this.player = value; }
        }

        private List<Unit> units = null;
        public List<Unit> Units
        {
            get { return this.units; }
            set { this.units = value; }
        }

        private List<Boss> bosses = null;
        public List<Boss> Bosses
        {
            get { return this.bosses; }
            set { this.bosses = value; }
        }

        private List<Follower> followers = null;
        public List<Follower> Followers
        {
            get { return this.followers; }
            set { this.followers = value; }
        }

        private List<NonFighter> nonFighters = null;
        public List<NonFighter> NonFighters
        {
            get { return this.nonFighters; }
            set { this.nonFighters = value; }
        }

        private List<Planet> planets = null;
        public List<Planet> Planets
        {
            get { return this.planets; }
            set { this.planets = value; }
        }

        private List<Ammo> ammo = null;
        public List<Ammo> Ammo
        {
            get { return this.ammo; }
            set { this.ammo = value; }
        }

        private SpriteBatch spriteBatch;
        public SpriteBatch SpriteBatch
        {
            get { return this.spriteBatch; }
            set { this.spriteBatch = value; }
        }

        public SharedContentManager Content
        {
            get { return this.mission.Campaign.Game.Content; }
        }

        public GraphicsDeviceManager Grpahics
        {
            get { return this.mission.Campaign.Game.Graphics; }
        }

        public GraphicsDevice GraphicsDevice
        {
            get { return this.mission.Campaign.Game.GraphicsDevice; }
        }

        public int ScreenWidth
        {
            get { return this.mission.Campaign.Game.ScreenWidth; }
        }

        public int ScreenHeight
        {
            get { return this.mission.Campaign.Game.ScreenHieght; }
        }

        private bool isContentLoaded = false;
        public bool IsContentLoaded
        {
            get { return this.isContentLoaded; }
            set { this.isContentLoaded = value; }
        }

        #endregion

        #region "Constructor"

        public Space(Mission mission)
        {

            this.mission = mission;

            this.units = new List<Unit>();
            this.bosses = new List<Boss>();
            this.followers = new List<Follower>();
            this.nonFighters = new List<NonFighter>();
            this.otherCameras = new List<Camera>();
            this.planets = new List<Planet>();
            this.ammo = new List<Ammo>(1000);

            this.player = new Player(this);
            this.mainCamera = new Camera(this);
            
        }
        
        #endregion

        #region "General Methods"

        public void Initialize()
        {

            this.spriteBatch = new SpriteBatch(this.mission.Campaign.Game.GraphicsDevice);
            
            this.player.MoveTo(new Vector3(0, 350, 0));

            this.mainCamera.DesiredPositionOffset = new Vector3(0,1000,2500);
            this.mainCamera.LookAtOffset = new Vector3(0, 500, 0);
            this.mainCamera.ChangeView(Camera.ViewType.ThirdPerson, this.player);
            this.mainCamera.Reset();

            // initialize other stuff

            this.FinaliseInitialization();

        }

        private void FinaliseInitialization()
        {

            foreach (Collidable c in this.units)
            {
                c.FinaliseInitialization();
            }
            foreach (Collidable c in this.planets)
            {
                c.FinaliseInitialization();
            }

        }

        public List<AssetToLoad> GetAssetsToLoad()
        {

            List<AssetToLoad> list = new List<AssetToLoad>();

            foreach (Collidable c in this.units)
            {
                list.AddRange(c.GetAssetsToLoad());
            }
            foreach (Collidable c in this.planets)
            {
                list.AddRange(c.GetAssetsToLoad());
            }

            // add common objects
            list.AddRange(Bullet.GetCommonAssetsToLoad());

            // add more assets

            return list;

        }

        Collidable ground;
        Asteroid asteroid;

        public void LoadContent(ContentLoader loader)
        {

            foreach (Collidable c in this.units)
            {
                c.LoadContent(loader);
            }
            foreach (Collidable c in this.planets)
            {
                c.LoadContent(loader);
            }

            // Load Common Contents
            Bullet.LoadCommonContent(loader);

            // add more loads

            //ground = new Collidable(this);
            //ground.LoadModel("Ground");
            asteroid = new Asteroid(this);
            asteroid.LoadContent(loader);

            

            this.isContentLoaded = true;

        }

        public void UnloadContent(SharedContentManager content)
        {

            foreach (Collidable c in this.units)
            {
                c.UnloadContent(content);
            }
            foreach (Collidable c in this.planets)
            {
                c.UnloadContent(content);
            }

            // Load Common Contents
            Bullet.UnloadCommonContent(content);

            // add more loads

        }

        #endregion

        #region "Methods"

        public void Update(GameTime gameTime)
        {

            KeyboardState keyboardState = Keyboard.GetState();
            MouseState mouseState = Mouse.GetState();

            // update units
            // --------------------------------------
            foreach (Collidable c in this.units)
            {
                c.Update(gameTime);
            }
            foreach (Collidable c in this.planets)
            {
                c.Update(gameTime);
            }
            foreach (Collidable c in this.ammo)
            {
                c.Update(gameTime);
            }


            // update cameras
            // --------------------------------------
            this.UpdateCameras(gameTime);

        }

        private void UpdateCameras(GameTime gameTime)
        {

            float dt = (float)gameTime.ElapsedGameTime.TotalSeconds;

            KeyboardState keyboardState = Keyboard.GetState();
            MouseState mouseState = Mouse.GetState();

            // update main camera
            // --------------------------------------
            if (keyboardState.IsKeyDown(Keys.F1))
            {
                this.mainCamera.ChangeView(Camera.ViewType.FirstPerson, this.player);
            }
            else if (keyboardState.IsKeyDown(Keys.F2))
            {
                this.mainCamera.ChangeView(Camera.ViewType.ThirdPerson, this.player);
                }

            //if (mouseState.X < this.ScreenWidth / 2)
            //{
            //    float w = this.ScreenWidth / 2.0f;
            //    this.player.Rotate(new Vector3(2 * this.player.RotationVelocity.X * dt * (w - mouseState.X) / w, 0, 0)); 
            //}
            //else if (mouseState.X > this.ScreenWidth / 2)
            //{
            //    float w = this.ScreenWidth / 2.0f;
            //    this.player.Rotate(new Vector3(-2 * this.player.RotationVelocity.X * dt * (mouseState.X - w) / w, 0, 0)); 
            //}

            this.mainCamera.Update(gameTime);


            // update other cameras
            // --------------------------------------
            foreach (Camera c in this.otherCameras)
            {
                c.Update(gameTime);
            }

        }

        public void Draw(GraphicsDevice g)
        {
            // add more draws

            
            foreach (Collidable c in this.units)
            {
                c.Draw(this.mainCamera, g);
            }
            foreach (Collidable c in this.planets)
            {
                c.Draw(this.mainCamera, g);
            }
            foreach (Collidable c in this.ammo)
            {
                c.Draw(this.mainCamera, g);
            }

            // testing
            //this.ground.Draw(this.mainCamera, g);
            //this.asteroid.Draw(this.mainCamera, g);

            // draw in 2d in screen coordinates
            this.Draw2D();


        }

        private void Draw2D()
        {

            this.spriteBatch.Begin();

            this.player.Draw2D(this.spriteBatch);

            this.spriteBatch.End();

        }

        public void AddBoss(Boss boss)
        {
            this.bosses.Add(boss);
        }

        public void AddFollower(Follower follower)
        {
            this.followers.Add(follower);
        }

        public void AddNonFighter(NonFighter nonfighter)
        {
            this.nonFighters.Add(nonfighter);
        }
        
        #endregion
                
    }
}
